// 实现这个项目的构建任务

const { src, dest, watch, series, parallel } = require('gulp')

// const sass = require('gulp-sass')
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin')
// const useref = require('gulp-useref')

// 压缩 html、js、css 文件
// const htmlmin = require('gulp-htmlmin') 
// const uglify = require('gulp-uglify') 
// const cleanCss = require('gulp-clean-css')

// 判断文件类型
// const gulpIf = require('gulp-if')

// 自动加载所有 gulp 插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

const del = require('del')

const browserSync = require('browser-sync')
const bs = browserSync.create()

// gulp 新版取消了同步代码模式，约定每个任务必须是异步任务
// 需要任务结束后显式调用回到函数来标记异步任务已完成
exports.default = done => {
  console.log('执行任务')
  done()
}

const clean = () => {
  // 此处 temp 目录是中间目录，用于存放第一次装换生成的文件，
  // dist 目录是 temp 目录经过 useref 进行文件合并与压缩后生成的最终文件目录
  return del(['dist', 'temp'])
}

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
}

const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env']}))
    .pipe(dest('temp'))
}

const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

const page = () => {
  return src('src/**/*.html', { base: 'src' })
    .pipe(plugins.swig({ data }))
    .pipe(dest('temp'))
}

const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

// 拷贝公共文件
const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}

// 使用 useref 可以使标记的多个文件合并成一个文件
const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // 对不同文件进行压缩，对不同类型文件进行判断
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      // 去除 space 空格
      collapseWhitespace: true,
      // 压缩 style 标签的 css
      minifyCSS: true,
      // 压缩 script 标签的 js
      minifyJS: true
    })))
    // 这里输出文件目录与上面读取文件目录不能一样，防止文件读写冲突
    .pipe(dest('dist'))
}

const devServer = () => {
  // 监视源代码目录 src 文件实现热更新与自动化构建
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)
  // 开发阶段不用每次都进行资源压缩，提高构建速度
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)
  
  bs.init({
    notify: false,
    port: 3000,
    // 监听目录文件变化
    // 不使用 files 字段，使用 .pipe(bs.reload({ stream: true })); 也可以
    files: 'dist/**',
    server: {
      // 可以指定多个服务目录，服务器回到多个目录下寻找资源
      baseDir: ['dist', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 在打包编译后的 dist 目录启动服务器
const proServer = () => {
  bs.init({
    notify: false,
    server: 'dist'
  })
}

const compile = parallel(style, script, page)

// 打包构建，parallel 是可以执行并行任务，顺序开启任务、同时执行
// 使用 series 串行任务，每次打包构建前先删除 dist 文件夹，再重新 compile

// 这里因为需要先 转换文件 到 temp 目录，useref 才能正常工作，所以需要增加 series 串行任务 
const build = series(clean, parallel(series(compile, useref), image, font, extra))

// 开发模式下，编译并启动服务器
const serve = series(compile, devServer)

// 打包编译，并启动服务器
const start = series(build, proServer)

module.exports = {
  clean,
  serve,
  build,
  start
}